function Moment = lpm(Data, MAR, Order)
%LPM Compute sample lower partial moments of Data.
%	Given NUMSERIES assets with NUMSAMPLES returns in a NUMSAMPLES x NUMSERIES
%	matrix Data, a scalar minimum acceptable return MAR, and one or more
%	non-negative moment orders in a NUMORDERS vector Order, compute lower
%	partial moments relative to MAR for each asset in a NUMORDERS x NUMSERIES
%	matrix Moment.
%
%		lpm(Data);
%		lpm(Data, MAR)
%		lpm(Data, MAR, Order);
%		Moment = lpm(Data, MAR, Order);
%
% Inputs:
%	Data - NUMSAMPLES x NUMSERIES matrix with NUMSAMPLES observations of
%		NUMSERIES asset returns.
%
% Optional Inputs:
%	MAR - Scalar minimum acceptable return (default MAR = 0). This is a cutoff
%		level of return such that all returns above MAR contribute nothing to
%		the lower partial moment.
%	Order - Either a scalar or an NUMORDERS-vector of non-negative integer
%		moment orders. If no order specified, default Order = 0, which is the
%		shortfall probability. Although this function will work for non-integer
%		orders and, in some cases, for negative orders, this falls outside
%		customary usage.
%
% Outputs:
%	Moment - NUMORDERS x NUMSERIES matrix of lower partial moments with
%		NUMORDERS Orders and NUMSERIES series, i.e., each row contains
%		lower-partial moments for a given order.
%
% Notes:
%	To compute upper partial moments, just reverse the signs of both Data and
%	MAR (do not reverse the sign of the output).
%
%	This function computes sample lower partial moments from data. To compute
%	expected lower partial moments for multivariate normal asset returns with
%	a specified mean and covariance, use elpm.
%
%	With lpm, you can compute various investment ratios such as Omega, Sortino,
%	Kappa, and Upside Potential, where:
%		Omega = lpm(-Data, -MAR, 1) ./ lpm(Data, MAR, 1);
%		Sortino = (mean(Data) - MAR) ./ sqrt(lpm(Data, MAR, 2));
%		Upside = lpm(-Data, -MAR, 1) ./ sqrt(lpm(Data, MAR, 2));
%
% References:
% [1] Vijay S. Bawa, "Safety-First, Stochastic Dominance, and Optimal
% Portfolio Choice," Journal of Financial and Quantitative Analysis, Vol.
% 13, No. 2, June 1978, pp. 255-271.
%
% [2] W. V. Harlow, "Asset Allocation in a Downside-Risk Framework,"
% Financial Analysts Journal, Vol. 47, No. 5, September/October 1991, pp.
% 28-40.
%
% [3] W. V. Harlow and K. S. Rao, "Asset Pricing in a Generalized
% Mean-Lower Partial Moment Framework: Theory and Evidence," Journal of
% Financial and Quantitative Analysis, Vol. 24, No. 3, September 1989, pp.
% 285-311.
%
% [4] Frank A. Sortino and Robert van der Meer, "Downside Risk," Journal
% of Portfolio Management, Vol. 17, No. 5, Spring 1991, pp. 27-31.
%
% See also elpm.

%	Copyright 1995-2006 The MathWorks, Inc.
%	$Revision: 1.1.6.2 $   $Date: 2006/06/16 20:09:52 $

% Step 1 - check arguments

% m = NUMSAMPLES
% n = NUMSERIES
% p = NUMORDERS

if nargin < 1 || isempty(Data)
	error('Finance:lpm:MissingInputArg', ...
		'Missing required input argument Data.');
end

if ~isscalar(Data) && isvector(Data) && isa(Data,'double')
	Data = Data(:);
	[m, n] = size(Data);
elseif ndims(Data) == 2 && min(size(Data)) > 1 && isa(Data,'double')
	[m, n] = size(Data);
else
	error('Finance:lpm:InvalidInputArg', ...
 		'Invalid format for Data. Must be a vector or matrix.');
end

if nargin < 2 || isempty(MAR)
	MAR = 0;
end

if ~isscalar(MAR) || ~isa(MAR, 'double') || isnan(MAR)
	error('Finance:lpm:InvalidInputArg', ...
		'Invalid format for MAR. Must be a finite scalar value.');
end

if nargin < 3 || isempty(Order)
	Order = 0;
else
	if isvector(Order) && isa(Order,'double') && all(Order >= 0)
		Order = Order(:);
	else
		error('Finance:lpm:InvalidInputArg', ...
			'Invalid format for Order. Must be a scalar or vector.');
	end
end

p = numel(Order);

q = all(isnan(Data));

% Step 2 - compute lower partial moments

Moment = zeros(p, n);

for j = 1:n
	if q(j)
		Moment(:,j) = NaN;
	else
		ii = 0;
		for i = 1:m
			if ~isnan(Data(i,j))
				ii = ii + 1;
				if Data(i,j) <= MAR
					Moment(:,j) = Moment(:,j) + (MAR - Data(i,j)) .^ Order;
				end
			end
		end
		Moment(:,j) = (1/ii) .* Moment(:,j);
	end
end
